/**
 * Create a new HashMap instance.
 * Inherit from Cloneable
 * @author	Wan Changhua
 * @version	2.01, 10/23/05 $Id: HashMap.js 35 2008-03-02 17:01:34Z dsonet $
 * @extends Cloneable
 * @class This is the map class.
 * @constructor
 */
function HashMap ()
{
	/**
	 * @private
	 */
	this._table = {};
}

$log.debug("hashMap");

var $p = Type.extend(HashMap, Cloneable).prototype;

/**
 * Returns an iterator of the values in this hashmap.
 * Use the Iterator methods on the returned object to fetch the elements
 * sequentially.
 * @id HashMap.prototype.entrys
 * @public
 * @return {Iterator} an iterator of the values in this hashmap.
 */
$p.entrys = function()
{
	var a = [], i = 0, h, e;
	for(h in this._table)
	{
		e = this._table[h];
		a[i++] = e.value;
	}
	return new Iterator(a);
}



/**
 * Returns the value to which the specified key is mapped in this idEntry
 * hash map, or <tt>null</tt> if the map contains no mapping for this key.
 * A return value of <tt>null</tt> does not <i>necessarily</i> indicate
 * that the map contains no mapping for the key; it is also possible that
 * the map explicitly maps the key to <tt>null</tt>. The
 * <tt>containsKey</tt> method may be used to distinguish these two cases.
 *
 * @param   key the key whose associated value is to be returned.
 * @return  the value to which this map maps the specified key, or
 *		  <tt>null</tt> if the map contains no mapping for this key.
 * @type Object
 */
$p.get = function(key)
{
	var h = Type.hashCode(key)
		, e = this._table[h];
	return (e == null) ? null : e.value;
}


/**
 * Returns <tt>true</tt> if this map contains no key-value mappings.
 *
 * @return <tt>true</tt> if this map contains no key-value mappings.
 * @type boolean
 */
$p.isEmpty = function ()
{
	return(this.size() == 0);
}


/**
 * Returns an iterator of the keys in this hashmap.
 *
 * @return  an iterator of the keys in this hashmap.
 * @type js.util.Iterator
 */
$p.keys = function()
{
	var a = [], i = 0, h, e;
	for(h in this._table)
	{
		e = this._table[h];
		a[i++] = e.key;
	}
	return new Iterator(a);
}


/**
 * Associates the specified value with the specified key in this map.
 * If the map previously contained a mapping for this key, the old
 * value is replaced.
 * @param key key with which the specified value is to be associated.
 * @param value value to be associated with the specified key.
 * @return previous value associated with specified key, or <tt>null</tt>
 *		   if there was no mapping for key.  A <tt>null</tt> return can
 *		   also indicate that the HashMap previously associated
 *		   <tt>null</tt> with the specified key.
 */
$p.put = function(key, value)
{
	var h = Type.hashCode(key)
		, oe = this._table[h]
		, oldValue = (oe == null) ? null : oe.value;
	this._table[h] = new Entry(key, value);
	return oldValue;
}

 /**
  * Removes the mapping for this key from this map if present.
  *
  * @param  key key whose mapping is to be removed from the map.
  * @return previous value associated with specified key, or <tt>null</tt>
  *		   if there was no mapping for key.  A <tt>null</tt> return can
  *		   also indicate that the map previously associated <tt>null</tt>
  *		   with the specified key.
  */
$p.remove = function(key)
{
	var h = Type.hashCode(key)
		, oe = this._table[h];
	delete this._table[h];
	return (oe == null) ? null : oe.value;
}


/**
 * Returns the number of key-value mappings in this map.
 *
 * @return the number of key-value mappings in this map.
 * @type int
 */
$p.size = function()
{
	var l = 0, h;
	for(h in this._table)
	{
		l += 1;
	}
	return l;
}

/**
 * Removes all mappings from this map.
 */
$p.clear = function()
{
	this._table = {};
}


/**
 * Returns <tt>true</tt> if this map maps one or more keys to the
 * specified value.
 *
 * @param value value whose presence in this map is to be tested.
 * @return <tt>true</tt> if this map maps one or more keys to the
 *		 specified value.
 * @type boolean
 */
$p.containsValue = function (value)
{
	for(var key in this._table)
	{
		if (this._table[key].value == value)
		{
			return true;
		}
	}
	return false;
}

/**
 * Returns <tt>true</tt> if this map contains a mapping for the
 * specified key.
 *
 * @param   key   The key whose presence in this map is to be tested
 * @return <tt>true</tt> if this map contains a mapping for the specified key.
 * @type boolean
 */
$p.containsKey = function(key)
{
	return (Type.hashCode(key) in this._table);
}

/**
 * Returns an array containing all of the elements in this list
 * in the correct order.
 *
 * @return an array containing all of the elements in this list
 * 		   in the correct order.
 * @type Array
 */
$p.toArray = function ()
{
	var entities = [], i = 0, h;
	for(h in this._table)
	{
		entities[i++] = this._table[h];
	}
	return entities;
}

/**
 * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
 * values themselves are not cloned.
 *
 * @return a shallow copy of this map.
 * @type HashMap
 */
$p.clone = function ()
{
	var map = new this;
	map._table = Cloneable.cloneObject(this._table);
	return map;
}

$p = null;